package com.pro.common.service.websocket.service;

import com.pro.baoyi.common.api.BaoyiConst;
import com.pro.common.api.model.ILoginInfo;
import com.pro.common.service.websocket.model.base.WebSocketMessage;
import com.pro.common.service.websocket.mq.WebsocketMqProducer;
import com.pro.common.service.websocket.util.IPAddressUtil;
import com.pro.framework.api.util.JSONUtils;
import com.pro.framework.api.util.StrUtils;
import com.pro.framework.cache.CacheManagerCenterRedis;
import com.pro.framework.cache.CombinedCacheManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;


@Component
@Slf4j
public class UserWebSocketHandler extends TextWebSocketHandler {

    private static final Map<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();

    @Autowired
    private WebsocketMqProducer websocketMqProducer;

    @Autowired
    private CacheManagerCenterRedis cacheManagerCenterRedis;

    @Autowired
    private CombinedCacheManager combinedCacheManager;

    @Autowired
    private IPAddressUtil ipAddressUtil;

    @Autowired
    private WebsocketEventService websocketEventService;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws IOException {
        ILoginInfo loginInfo = (ILoginInfo) session.getAttributes().get("loginInfo");
        Object rawTokenObj = session.getAttributes().get("token");
        String connId = UUID.randomUUID().toString();
        // 保存 session 属性
        session.getAttributes().put("connId", connId);
        // 保存 session 到本地 SESSION_POOL
        SESSION_POOL.put(connId, session);
        if (loginInfo == null || rawTokenObj == null) return;
        String rawToken = rawTokenObj.toString();

        Long userId = loginInfo.getId();
        String token = rawToken.replaceFirst("(?i)^Bearer\\s+", "");
        String tokenMd5 = StrUtils.md5(token);
        boolean canLogin = false;

        if (rawToken.isEmpty() || userId == null) return;
        // 本地记录
        WebSocketMessage websocketMessage = websocketEventService.getWebSocketMessage(userId, loginInfo, connId, tokenMd5);

        // 给客户端确认
        session.sendMessage(new TextMessage(JSONUtils.toString(websocketMessage)));


        session.getAttributes().put("token", tokenMd5);
    }



    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        String connId = (String) session.getAttributes().get("connId");
        String token = (String) session.getAttributes().get("token");
        ILoginInfo loginInfo = (ILoginInfo) session.getAttributes().get("loginInfo");
        WebSocketMessage webSocketMessage = websocketEventService.handleMessage(connId, token, loginInfo, session, message);
        session.sendMessage(new TextMessage(JSONUtils.toString(webSocketMessage)));
    }



    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        String connId = (String) session.getAttributes().get("connId");
        String tokenMd5 = (String) session.getAttributes().get("token");
        if (tokenMd5 == null || connId == null) return;
        ILoginInfo loginInfo = (ILoginInfo) session.getAttributes().get("loginInfo");
        Long userId = (loginInfo != null) ? loginInfo.getId() : null;
        String userIdStr = userId != null ? userId.toString() : null;
        SESSION_POOL.remove(connId);
        websocketEventService.closeClean(userId, loginInfo, connId, tokenMd5);
    }



    // 推送给指定用户
    public void sendToUser(String userId, String payload) throws IOException {
        Set<String> tokenMd5s = cacheManagerCenterRedis.getSetMembers(BaoyiConst.CacheKey.LOGIN_LIMIT_USER, userId);
        if (tokenMd5s == null || tokenMd5s.isEmpty()) return;

        for (Object tokenObj : tokenMd5s) {
            String tokenMd5 = tokenObj.toString();
            Map<Object, Object> connMap = cacheManagerCenterRedis.getHashAll(BaoyiConst.CacheKey.LOGIN_LIMIT_TOKEN, tokenMd5);
            if (connMap != null) {
                for (Object connIdObj : connMap.keySet()) {
                    String connId = connIdObj.toString();
                    WebSocketSession sess = SESSION_POOL.get(connId);
                    if (sess != null && sess.isOpen()) {
                        try {
                            sess.sendMessage(new TextMessage(payload));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }


}

